package study.springcloud.gateway.support.utils;

import cn.hutool.core.map.MapUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;

import java.util.Map;
import java.util.Objects;

@Slf4j
public final class WebUtils {

    public static final String X_REQUEST_ID = "X-Request-Id";

    private WebUtils() {
    }

    //==============================
    // 请求和响应
    //==============================

    /**
     * 获取 ServerHttpRequest
     */
    public static ServerHttpRequest getServerHttpRequest(ServerWebExchange exchange) {
        ServerHttpRequest request = exchange.getRequest();
        return request;
    }

    /**
     * 获取 ServerHttpResponse
     */
    public static ServerHttpResponse getServerHttpResponse(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        return response;
    }

    //==============================
    // 请求头
    //==============================

    /**
     * 是否为只读头部
     */
    public static boolean isReadOnly(HttpHeaders headers) {
        // ReadOnlyHttpHeaders class package access, so routing by name
        String cName = headers.getClass().getSimpleName();
        log.info(">>>>>> 请求头类型: {}", cName);
        return Objects.equals("ReadOnlyHttpHeaders", cName);
    }

    /**
     * 获取请求头
     */
    public static HttpHeaders getRequestHeaders(ServerWebExchange exchange) {
        ServerHttpRequest request = exchange.getRequest();
        return request.getHeaders();
    }

    /**
     * 获取请求头
     */
    public static String getRequestHeader(ServerWebExchange exchange, String name) {
        HttpHeaders headers = getRequestHeaders(exchange);
        String value = null;
        if (Objects.nonNull(headers)) {
            value = headers.getFirst(name);
        }
        return value;
    }

    /**
     * 添加请求头
     */
    public static void addRequestHeader(ServerWebExchange exchange, String name, String value) {
        addRequestHeaders(exchange, MapUtil.of(name, value));
    }

    /**
     * 添加请求头
     */
    public static void addRequestHeaders(ServerWebExchange exchange, Map<String, String> header) {
        ServerHttpRequest request = getServerHttpRequest(exchange);
        HttpHeaders headers = request.getHeaders();
        if (Objects.nonNull(headers) && isReadOnly(headers)) {
            //log.warn("readonly request header, so mutate");
            request.mutate().headers(myHeaders -> {
                header.entrySet()
                        .forEach(e -> myHeaders.add(e.getKey(), e.getValue()));
            }).build();
        } else {
            header.entrySet()
                    .forEach(e -> headers.add(e.getKey(), e.getValue()));
        }
    }

    //==============================
    // 响应头
    //==============================

    /**
     * 获取响应头
     */
    public static HttpHeaders getResponseHeaders(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        return response.getHeaders();
    }

    /**
     * 获取响应头
     */
    public static String getResponseHeader(ServerWebExchange exchange, String name) {
        HttpHeaders headers = getResponseHeaders(exchange);
        String value = null;
        if (Objects.nonNull(headers)) {
            value = headers.getFirst(name);
        }
        return value;
    }

    /**
     * 添加响应头
     */
    public static void addResponseHeader(ServerWebExchange exchange, String name, String value) {
        addResponseHeaders(exchange, MapUtil.of(name, value));
    }

    /**
     * 添加响应头
     */
    public static void addResponseHeaders(ServerWebExchange exchange, Map<String, String> headerMap) {
        ServerHttpResponse response = getServerHttpResponse(exchange);
        HttpHeaders headers = response.getHeaders();
        if (Objects.nonNull(headers) && isReadOnly(headers)) {
            //log.warn("readonly response header, so bad");
            headerMap.entrySet()
                    .forEach(e -> {
                        headers.add(e.getKey(), e.getValue());
                    });
        } else {
            headerMap.entrySet()
                    .forEach(e -> {
                        headers.add(e.getKey(), e.getValue());
                    });
        }
    }

    //==============================
    // Cookie
    //==============================

    /**
     * 获取 cookie 值
     */
    public static String getCookieValue(ServerWebExchange exchange, String name) {
        ServerHttpRequest request = getServerHttpRequest(exchange);
        MultiValueMap<String, HttpCookie> cookies = request.getCookies();
        String value = null;
        if (Objects.nonNull(cookies)) {
            HttpCookie cookie = cookies.getFirst(name);
            if (Objects.nonNull(cookie)) {
                value = cookie.getValue();
            }
        }
        return value;
    }

    //==============================
    // Attribute
    //==============================

    /**
     * 放置属性
     */
    public static <T> void putAttr(ServerWebExchange exchange, String key, T value) {
        Map<String, Object> attrs = exchange.getAttributes();
        attrs.put(key, value);
    }

    /**
     * 获取属性
     */
    public static <T> T getAttr(ServerWebExchange exchange, String key) {
        return exchange.getAttribute(key);
    }

    /**
     * 获取 Request Id
     *
     * @param exchange
     * @return String
     */
    public static String getRequestId(ServerWebExchange exchange) {
        return getRequestHeader(exchange, X_REQUEST_ID);
    }
}
